package comp353Games;

import java.util.Arrays;

/**
 * Nim.java describes a game of Nim. More information about this game is
 * available here: http://en.wikipedia.org/wiki/Nim
 *
 * @author Tyler Radley, Andre Harvey, Deanna Fink
 * @version 4/30/12
 */
public class Nim implements GameModel {

    //An array of heaps containing sticks
    private int[] heaps;

    /**
     * Constructor for a default basic game with four heaps of sizes 3, 5, 7 and
     * 9
     */
    public Nim() {
        // initialize instance variables
        this.heaps = new int[]{3,5,7,9};
    }

    /**
     * Constructor for a game of Nim in which the user can specify the number
     * and size of heaps
     *
     * @param heap An array containing the size of each heap
     */
    public Nim(int[] heaps) {

        //don't alias!  Create a new array!
        this.heaps= heaps;
    }

    /**
     * creates a clone of heaps without allowing the user to clone it
     *
     * @return a clone of heaps
     */
    public int[] heapsClone() {
        int[] heapsClone = new int[heaps.length];
        for (int i = 0; i < heaps.length; i++) {
            heapsClone[i] = heaps[i];
        }
        return heapsClone;
    }

    @Override
    public String getName() {
        return "Nim";
    }

    @Override
    public Nim getNewGame() {
        return new Nim();
    }

    @Override
    public NimDisplay getDisplay(GameModel game) {
        return new NimDisplay(game);
    }

    @Override
    public boolean hasMovesRemaining(int Player) {
        for (int i = 0; i < heaps.length; i++) {
            if (heaps[i] > 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String[] getInstructions(int currentPlayer) {
        String[] instructions = new String[3];
        instructions[2] = "Player " + currentPlayer;
        instructions[0] = "Welcome to Nim!  ";
        instructions[1] = instructions[2]
                + ", select a stick to remove it and all sticks to it's right.";

        return instructions;
    }

    @Override
    public int hashCode() {
        int code = 0;
        for (int i = 0; i < this.heaps.length; i++) {
            code += (this.heaps[i] + 1) * Math.pow(3, i);
        }
        return code;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Nim other = (Nim) obj;
        if (!Arrays.equals(this.heaps, other.heaps)) {
            return false;
        }
        return true;
    }

    @Override
    public String save() {
        String saveText = "<Nim>\n";
        saveText += "<heaps>\n";
        saveText += heaps.length + "x";
        for (int i = 0; i < heaps.length; i++) {
            saveText += this.heaps[i] + ".";
        }
        saveText += "\n</heaps>\n";
        saveText += "</Nim>";
        return saveText;
    }

    @Override
    public Nim load(String fileString) {

        int index = 12;
        String lengthString = "";
        while (fileString.substring(index, index+1).equals("x")==false) {
            lengthString += fileString.charAt(index);
            index++;
        }
        index++;
        int lengthValue = Integer.parseInt(lengthString);
        int[] newBoard = new int[lengthValue];

        for (int i = 0; i < lengthValue; i++) {
            String integerHelper = "";
            while (fileString.substring(index, index+1).equals(".")==false) {
                integerHelper += fileString.charAt(index);
                 System.out.println(integerHelper);
                index++;
            }
            newBoard[i] = Integer.parseInt(integerHelper);
            index++;
        }
        return new Nim(newBoard);
    }

    /**
     * Returns a string version of this.
     *
     * @param indent A string of spaces meant to position the following text
     * away from the left margin.
     * @return a string version of the game with an indentation.
     */
    public String toString(String indent) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(indent + "Nim\n");
        stringBuilder.append(indent + "|");
        for (int i = 0; i < this.heaps.length; i++) {
            for (int j = 0; j < heaps[i]; j++) {
                stringBuilder.append(" |");
            }
            stringBuilder.append("\n");
        }

        stringBuilder.append("\n");
        return stringBuilder.toString();
    }

    @Override
    public String toString() {
        return this.toString("");
    }

    @Override
    public boolean validMove(int[] gamePress, int[] gameRelease,
            int[] gameClick, int currentPlayer) {

        if (gameClick[0] == -1 && gameClick[1] == -1) {
            return false;
        }
        return true;
    }

    @Override
    public GameModel updateGame(int[] gamePress, int[] gameRelease,
            int[] gameClick, int currentPlayer) {

        heaps[gameClick[0]] = gameClick[1];
        return new Nim(heaps);
    }

    @Override
    public int[] mousePressedHandler(int xPosition, int yPosition) {
        return null;
    }

    @Override
    public int[] mouseReleasedHandler(int xPosition, int yPosition) {
        return null;
    }

    @Override
    public int[] mouseClickedHandler(int xPosition, int yPosition, int currentPlayer) {
        System.out.println(xPosition + "," + yPosition);
        int boundsIndex = 0;
        int[] coordinate = new int[2];
        for (int i = 0; i < this.heaps.length; i++) {
            for (int j = 0; j < this.heaps[i]; j++) {
                boundsIndex++;
            }
            boundsIndex++;
        }
        //Keeps track of the xPosition and yPosition coordinates of
        //  the top left corner of each stick
        int[] xBounds = new int[boundsIndex];
        int[] yBounds = new int[boundsIndex];

        for (int i = 0; i < heaps.length; i++) {
            for (int j = 0; j < this.heaps[i]; j++) {
                xBounds[j] = j * 20 + 18;
                yBounds[i] = i * 70 + 17;
                if (xPosition > xBounds[j] && xPosition < xBounds[j] + 10
                        && yPosition > yBounds[i]
                        && yPosition < yBounds[i] + 50) {
                    //Assign the coordinates of the stick that was selected
                    coordinate[0] = (int) (Math.floor((yPosition - 17) / 70));
                    coordinate[1] = (int) (Math.floor((xPosition - 18) / 20));
                    return coordinate;
                }
            }
        }
        //if invalid coordinates chosen, return the array {-1, -1}
        coordinate[0] = -1;
        coordinate[1] = -1;
        return coordinate;
    }
}

